Add per-container Linux Secret Service for VS Code SecretStorage#22
Add per-container Linux Secret Service for VS Code SecretStorage#22Copilot wants to merge 4 commits into
Conversation
|
@copilot lets add a note to the README about how to use the devcontainer master password without Codespaces. |
Added a "Setting a master password" section to the README in 3acc730. It covers forwarding |
| "remoteEnv": { | ||
| "XDG_RUNTIME_DIR": "/tmp/runtime-1000", | ||
| "DBUS_SESSION_BUS_ADDRESS": "unix:path=/tmp/runtime-1000/bus", | ||
| "KEYRING_PASSWORD": "${localEnv:KEYRING_PASSWORD}" |
There was a problem hiding this comment.
@copilot are there any risks about keeping this in the environment? is this still more secure than plaintext or no keyring password?
There was a problem hiding this comment.
Good question — yes, it's still strictly better than plaintext or an empty password, with one caveat. I documented the trade-offs in e365430:
- At rest (the threat this targets): the vault is AES-encrypted with the password, so a snapshot/backup/stolen disk image is useless without it. Empty password = trivially decryptable; plaintext fallback = no protection.
- At runtime: the password sits in the remote user's environment, so any process running as that user can read it (
/proc/<pid>/environ) and unlock the vault. But that same process could already read the secrets directly via SecretStorage, so it doesn't lower the bar below where it already is. - Provenance: it's injected at runtime via
${localEnv:...}/ Codespaces secret, never baked into the image or committed. The main thing to avoid is hardcoding it indevcontainer.jsonor leaving it in shell history.
Net: empty password protects almost nothing at rest; a real KEYRING_PASSWORD meaningfully protects the on-disk vault while leaving runtime exposure unchanged.
On Linux, VS Code (and extensions like GitHub Copilot) silently fall back to a plaintext
secrets.jsonforSecretStoragewhen no Secret Service backend is reachable. This adds a self-contained, headlessgnome-keyringsetup inside the container so credentials land in an AES-encrypted vault—no host keychain forwarding.Changes
Dockerfile— apt layer addinggnome-keyring,libsecret-1-0,libsecret-tools,dbus,python3-jeepney.keyring-init.sh— idempotent start hook: launches a private DBus session bus on a fixed socket, startsgnome-keyring-daemon --components=secrets, bootstraps the default collection, persists env, and probes a round-trip. Reuses live daemons; degrades gracefully (exit 0) on failure.keyring-bootstrap.py— creates the persistentdefaultcollection via gnome-keyring's non-specCreateWithMasterPassword(the specCreateCollectionpath needs a GTK prompter that containers lack). No-ops when the alias already resolves.devcontainer.json— staticremoteEnv(XDG_RUNTIME_DIR,DBUS_SESSION_BUS_ADDRESSfor UID 1000) so every VS Code Server child finds the same bus, pluspostStartCommand/postAttachCommandhooks.README.md— documents the secret-storage capability.Notes for reviewers
remoteEnvis load-bearing: without it extensions race the start hook and mark the session as basic-store.KEYRING_PASSWORD(e.g. via a Codespaces user secret) to raise the bar. The script feeds it to both bootstrap and--unlock.1000(node) is hardcoded in theremoteEnvpaths; would need substitution on a different base image.